#include <sys/timeb.h>
#include <iostream>

#include <OgreWindowEventUtilities.h>
#include <OgreFrameListener.h>
#include <OgreRenderWindow.h>

#include "Core.h"
#include "Assignment2.h"
//#include "InputControl.h

namespace {
	///WindowListener is created by the Core to notify the render loop of window closure.
	class WindowListener : public Ogre::WindowEventListener, public Ogre::FrameListener {
		private:
			bool windowOpen;

		public:
			WindowListener(void)
				: windowOpen(true)
			{}

			//When the window's closed; notify for no more rendering
			void windowClosed(Ogre::RenderWindow* win) {
				windowOpen = false;
			}

			//FrameListener portion--return windowOpen, besically
			bool frameStarted(const Ogre::FrameEvent& evt) {
				return windowOpen;
			}
			bool frameRenderingQueued(const Ogre::FrameEvent& evt) {
				return windowOpen;
			}
			bool frameEnded(const Ogre::FrameEvent& evt) {
				return windowOpen;
			}
	};
}

static WindowListener closingListener;

using namespace pong;

static const char PLUGINS_FILE[] = "plugins.cfg";

Core::Core(const Ogre::String& configFolder)
	: ogreRoot(new Ogre::Root(PLUGINS_FILE)),
		config(configFolder, ogreRoot),
        stateMan(this), inputMan(&stateMan),
        running(true), updateInterval(0),
        serverPortNum(9090), serverHostName(0)
{
	config.applyVideoSettings(); //Set the initial settings

	//Create the window
	renderWin = ogreRoot->initialise(true, "Pong3D");

	inputMan.init(renderWin);

    // Add the closing listener so the game can be shutdown on window close
    Ogre::WindowEventUtilities::addWindowEventListener(renderWin, &closingListener);
    ogreRoot->addFrameListener(&closingListener);

    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

Core::~Core(void) {
	delete ogreRoot;
}

int Core::run(int argc, char** args) {
    if (argc > 1) {
        serverHostName = args[1];
    }

    Assignment2 assignmentState;
    stateMan.push(/*&btTest);*/&assignmentState);

	//Run our own loop--pump messages and render frames
	timeb curTime, prevTime;
	ftime(&prevTime);
	while(running) {

		//Pump window events
		Ogre::WindowEventUtilities::messagePump();
        inputMan.capture();
		//Render a frame
		running = running && ogreRoot->renderOneFrame();

		ftime(&curTime);
		const short  millis = curTime.millitm - prevTime.millitm;
		const time_t secs   = curTime.time - prevTime.time;
		updateInterval = double(secs * 1000 + millis) / 1000.0; //TODO: something nicer?

		stateMan.update();

		prevTime = curTime;
	}

    stateMan.pop();

	return 0;
}

void Core::halt(void) {
    running = false;
}